﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using ComputerArchitecture.Core;
using ComputerArchitecture.Core.Logging;
using ComputerArchitecture.Numbers;
using ComputerArchitecture.Units.Integers.Signed.Interfaces;

namespace ComputerArchitecture.Units.Integers.Signed.Implementations
{
    public class SignedNegateUnit : LoggingObject, ISignedNegateUnit
    {
        #region Fields

        private readonly ISignedAdderUnit _adderUnit;

        #endregion

        #region Constructors

        public SignedNegateUnit(ILoggingService loggingService, ISignedAdderUnit adderUnit) : base(loggingService)
        {
            ArgumentValidator.NullValidate(adderUnit, "adderUnit");
            _adderUnit = adderUnit;
        }

        public SignedNegateUnit(ILoggingService loggingService)
            : this(loggingService, new SignedAdderUnit(loggingService))
        {
        }

        #endregion

        #region Methods

        IBitNumber INegateUnit.Negate(IBitNumber value, out NegateSpecialCase specialCase, out bool hasError)
        {
            return this.Negate((ISignedBitNumber) value, out specialCase, out hasError);
        }

        public ISignedBitNumber Negate(ISignedBitNumber value, out NegateSpecialCase specialCase, out bool hasError)
        {
            ArgumentValidator.NullValidate(value);
            ISignedBitNumber zero = SignedBitNumber.GetZero(value.Size);
            if (value.Equals(zero))
            {
                hasError = true;
                specialCase = NegateSpecialCase.Zero;
                this.LoggingService.LogWarning("Warning! Try to negate zero ({0:d4})", value);
                return zero;
            }
            ISignedBitNumber min = SignedBitNumber.GetMin(value.Size);
            if (value.Equals(min))
            {
                hasError = true;
                specialCase = NegateSpecialCase.MaxNegativeValue;
                this.LoggingService.LogWarning("Warning! Try to negate min value ({0:d4})", value);
                return min;
            }
            hasError = false;
            specialCase = NegateSpecialCase.None;
            ISignedBitNumber negate = (ISignedBitNumber)value.Clone();
            negate.Negate();
            ISignedBitNumber one = SignedBitNumber.GetOne(value.Size);
            bool overflow;
            return _adderUnit.Add(negate, one, out overflow);
        }

        #endregion
    }
}
